home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / inventor / ivcalc / ivcalc.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  52.4 KB  |  2,197 lines

  1. /*
  2.  * Copyright 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. char ident[] = "@(#)IVcalc Version 1.0";
  18. /*----------------------------------------------------------------
  19.  * 
  20.  *  ivcalc - 3D calculator built with the Inventor graphics toolkit
  21.  *         
  22.  *  
  23.  *  03/93  John Magdziarz, Silicon Graphics, Inc.
  24.  * 
  25.  *----------------------------------------------------------------*/
  26.  
  27. #include <ctype.h>
  28. #include <iostream.h>
  29. #include <X11/StringDefs.h>
  30.  
  31. #include <sys/types.h>
  32. #include <sys/prctl.h>
  33. #include <sys/schedctl.h>
  34. #include <audio.h>
  35. #include <audiofile.h>
  36.  
  37. #include <Inventor/Xt/SoXt.h>
  38. #include <Inventor/Xt/SoXtRenderArea.h>
  39. #include <Inventor/Xt/SoXtComponent.h>
  40. #include <Inventor/SoDB.h>
  41. #include <Inventor/SbLinear.h>
  42. #include <Inventor/SoInput.h>
  43. #include <Inventor/SoOutput.h>
  44. #include <Inventor/nodes/SoEventCallback.h>
  45. #include <Inventor/nodes/SoSelection.h>
  46. #include <Inventor/sensors/SoSensor.h>
  47. #include <Inventor/details/SoDetail.h>
  48. #include <Inventor/events/SoMouseButtonEvent.h>
  49. #include <Inventor/events/SoEvent.h>
  50. #include <Inventor/events/SoKeyboardEvent.h>
  51. #include <Inventor/actions/SoSearchAction.h>
  52. #include <Inventor/actions/SoGetMatrixAction.h>
  53. #include <Inventor/actions/SoGetBoundingBoxAction.h>
  54. #include <Inventor/actions/SoWriteAction.h>
  55. #include <Inventor/actions/SoRayPickAction.h>
  56. #include <Inventor/nodes/SoLabel.h>
  57. #include <Inventor/nodes/SoGroup.h>
  58. #include <Inventor/nodes/SoFont.h>
  59. #include <Inventor/nodes/SoText3.h>
  60. #include <Inventor/nodes/SoTransform.h>
  61. #include <Inventor/nodes/SoTranslation.h>
  62. #include <Inventor/nodes/SoRotationXYZ.h>
  63. #include <Inventor/nodes/SoScale.h>
  64. #include <Inventor/nodes/SoSeparator.h>
  65. #include <Inventor/nodes/SoPerspectiveCamera.h>
  66. #include <Inventor/nodes/SoMaterial.h>
  67. #include <Inventor/nodes/SoDirectionalLight.h>
  68. #include <Inventor/nodes/SoCone.h>
  69. #include <Inventor/nodes/SoCube.h>
  70. #include <Inventor/nodes/SoTexture2.h>
  71. #include <Inventor/nodes/SoSwitch.h>
  72. #include <Inventor/nodes/SoPickStyle.h>
  73. #include <Inventor/manips/SoTrackballManip.h>
  74. #include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
  75. #include <Inventor/SoPickedPoint.h>
  76. #include <Inventor/sensors/SoTimerSensor.h>
  77.  
  78. #include "ivcalc.h"
  79.  
  80. //  ****************************************
  81. //  ******  xcalc code and variables  ******
  82. //  ****************************************
  83.  
  84. const int MAXDISP = 10;
  85. #define STACKMAX 32
  86. static int opstack[STACKMAX];
  87. static int opsp;
  88. static double numstack[STACKMAX];
  89. static int numsp;
  90. static int entered=1;  /* true if display contains a valid number.
  91.                           if==2, then use 'dnum', rather than the string
  92.                           stored in the display.  (for accuracy) 
  93.                           if==3, then error occurred, only CLR & AC work */
  94. /* entered seems to be overloaded - dmc */
  95. static int lift_enabled = 0;    /* for rpn mode only */
  96.  
  97. #define DEG 0        /* DRG mode.  used for trig calculations */
  98. #define RAD 1
  99. #define GRAD 2
  100. static int CLR    =0;  /* CLR clears display.  if 1, clears acc, also */
  101. static int Dpoint=0;  /* to prevent using decimal pt twice in a # */
  102. static int clrdisp=1;  /* if true clears display before entering # */
  103. static int lastop =kCLR;
  104. static int memop  =kCLR;
  105. static int exponent=0;
  106. static double acc =0.0;
  107. static double dnum=0.0;
  108. static int rpn = 0;
  109. int errno = FALSE;
  110. int flagINV, flagPAREN, flagM, drgmode;     /* display flags */
  111.  
  112. #define XCALC_PRE_OP(keynum) if (pre_op(keynum)) return;
  113. #ifndef PI              /* sometimes defined in math.h */
  114. #define PI          3.14159265358979
  115. #endif
  116. #define E           2.71828182845904
  117. static double drg2rad=PI/180.0;  /* Conversion factors for trig funcs */
  118. static double rad2drg=180.0/PI;
  119. #define XCALC_MEMORY 10
  120. static double mem[XCALC_MEMORY] = { 0.0 };
  121.  
  122.  
  123. static void DrawDisplay();
  124. static void post_op();
  125. static void PushNum( double );
  126. static double PopNum();
  127. static void PushOp( int );
  128. static int  PopOp();
  129. static void numeric( int );
  130. static void digit( int );
  131. static void subtract( int );
  132. static void add( int );
  133. static void divide( int );
  134. static void multiply( int );
  135. static void cosine( int );
  136. static void sine( int );
  137. static void tangent( int );
  138. static void inverse( int );
  139. static void e( int );
  140. static void pi( int );
  141. static void epower( int );
  142. static void factorial( int );
  143. static void naturalLog( int );
  144. static void logarithm( int );
  145. static void scientific( int );
  146. static void square( int );
  147. static void squareRoot( int );
  148. static void leftParen( int );
  149. static void rightParen( int );
  150. static void negate( int );
  151. static void clearit( int );
  152. static void decimal( int );
  153. static void degree( int );
  154. static void enter( int );
  155. static void equal( int );
  156. static void reciprocal( int );
  157. static void squareRoot( int );
  158. static void power( int );
  159. static void quit( int );
  160. static void off( int );
  161. static void back( int );
  162. static void twoop( int );
  163. static void oneop( int );
  164. static void sum( int );
  165. static void memf( int );
  166. static void twof( int );
  167. static int isopempty();
  168. static void parse_double (char *, char *, double *);
  169. static int  priority( int );
  170. static void clearf();
  171. static void offf();
  172. static void ResetCalc();
  173. static void eef();
  174. static void invf();
  175. static void bkspf();
  176. static void decf();
  177. static void drgf();
  178. static void ClearStacks();
  179. static int pre_op( int );
  180. static void entrf();
  181. static void equf();
  182. static void negf();
  183. static void lparf();
  184. static void rparf();
  185. static void Quit();
  186. static void growCalc( int );
  187.  
  188.  
  189. //  ****************************************
  190. //  ******  IVcalc code and variables  *****
  191. //  ****************************************
  192.  
  193. const int BTNDEPTH = 20;
  194. const float BTNSLOP = .20;
  195. float TIMERFREQ = 0.03;
  196. const float TEXTDEPTH = 8.0;
  197.  
  198. /* AUDIO DEFINES */
  199. #define BUFFERSIZE 4000            /* Size of output sample buffer. */
  200.  
  201.  
  202. typedef struct Btn {
  203.         int x; 
  204.         int y;
  205.         float z;
  206.         char *label;
  207.         int colIndex;
  208.         int btnVal;
  209.         SoSeparator *bOrigin;
  210.         void (*func)( int );
  211.        };
  212.  
  213. enum ActivateType { HIGHLIGHT, ANIMATE };
  214.  
  215. struct PickData {
  216.         int btnIndex;
  217.         Boolean grow;
  218.         SoPerspectiveCamera *camera;
  219.         SoNode *root;
  220.         SoTranslation *xlateBtn;
  221.         SoTranslation *xlateKeypad;
  222.         SoSwitch *xtraBtns;
  223.         SoMaterial *mtlBtn;
  224.         SoTransform *xformBase;
  225.         SbViewportRegion vp;
  226.         char *keyCode;
  227.         enum ActivateType activateType;
  228.        };
  229.  
  230. struct Dim {
  231.         float width;
  232.         float height;
  233.         float depth;
  234.        };
  235.  
  236. struct Pos {
  237.         float x;
  238.         float y;
  239.         float z;
  240.        };
  241.  
  242. struct Col {
  243.         float r;
  244.         float g;
  245.         float b;
  246.        };
  247.  
  248. const int NUMROWS = 5;
  249. const int NUMCOLS = 4;
  250. const int NUMXTRACOLS = 4;
  251.  
  252. const float rowOff[] =  { 0, -120, -240, -360, -480 };
  253. const float colOff[] =  { 0, 120, 240, 360, -120, -240, -360, -480 };
  254. Col calcCols[20];
  255.  
  256.  
  257. Btn btns[] = {
  258.               { 0, 0, 0, "AC",  1, -1,     NULL, off }, 
  259.               { 1, 0, 0, "CE",  1, kCLR,   NULL, clearit },
  260.               { 2, 0, 0, "G",   1, -1,     NULL, growCalc },
  261.               { 3, 0, 0, "/",   1, kDIV,   NULL, divide },
  262.               { 0, 1, 0, "7",   0, kSEVEN, NULL, digit }, 
  263.               { 1, 1, 0, "8",   0, kEIGHT, NULL, digit },
  264.               { 2, 1, 0, "9",   0, kNINE,  NULL, digit },
  265.               { 3, 1, 0, "*",   1, kMUL,   NULL, multiply },
  266.               { 0, 2, 0, "4",   0, kFOUR,  NULL, digit }, 
  267.               { 1, 2, 0, "5",   0, kFIVE,  NULL, digit },
  268.               { 2, 2, 0, "6",   0, kSIX,   NULL, digit },
  269.               { 3, 2, 0, "-",   1, kSUB,   NULL, subtract },
  270.               { 0, 3, 0, "3",   0, kTHREE, NULL, digit }, 
  271.               { 1, 3, 0, "2",   0, kTWO,   NULL, digit },
  272.               { 2, 3, 0, "1",   0, kONE,   NULL, digit },
  273.               { 3, 3, 0, "+",   1, kADD,   NULL, add },
  274.               { 0, 4, 0, "0",   0, kZERO,  NULL, digit }, 
  275.               { 1, 4, 0, "+/-", 0, -1,     NULL, negate },
  276.               { 2, 4, 0, ".",   0, kDEC,   NULL, decimal },
  277.               { 3, 4, 0, "=",   1, kEQU,   NULL, equal },
  278.  
  279.               { 4, 0, 0, "BS",  1, -1,     NULL, back },
  280.               { 4, 1, 0, "INV", 1, -1,     NULL, inverse },
  281.               { 4, 2, 0, "e",   1, kTHREE, NULL, e }, 
  282.               { 4, 3, 0, "e^x", 1, kTWO,   NULL, epower },
  283.               { 4, 4, 0, "1/x", 1, kONE,   NULL, reciprocal },
  284.  
  285.               { 5, 0, 0, ")",   1, kADD,   NULL, rightParen },
  286.               { 5, 1, 0, "sin", 1, kZERO,  NULL, sine }, 
  287.               { 5, 2, 0, "EE",  1, -1,     NULL, scientific },
  288.               { 5, 3, 0, "x^2", 1, kDEC,   NULL, square },
  289.               { 5, 4, 0, "x!",  1, kEQU,   NULL, factorial },
  290.  
  291.               { 6, 0, 0, "(",   1, kADD,   NULL, leftParen },
  292.               { 6, 1, 0, "cos", 1, kZERO,  NULL, cosine }, 
  293.               { 6, 2, 0, "log", 1, -1,     NULL, logarithm },
  294.               { 6, 3, 0, "DRG", 1, kDEC,   NULL, degree },
  295.               { 6, 4, 0, "y^x", 1, kEQU,   NULL, power },
  296.  
  297.               { 7, 0, 0, "Off", 1, kADD,   NULL, quit },
  298.               { 7, 1, 0, "tan", 1, kZERO,  NULL, tangent }, 
  299.               { 7, 2, 0, "ln",  1, -1,     NULL, naturalLog },
  300.               { 7, 3, 0, "pi",  1, kDEC,   NULL, pi },
  301.               { 7, 4, 0, "sqr", 1, kEQU,   NULL, squareRoot }
  302.              };
  303.  
  304.  
  305.  
  306. static struct resources {
  307.   Boolean      maxWhizzy;
  308.   Boolean      textures;
  309.   Boolean      outputFile;
  310.   Boolean      niceBtns;
  311.   Boolean      niceBase;
  312.   Boolean      thickText;
  313.   Boolean      kbdAnimate;
  314.   Boolean      highlight;
  315.   Boolean      audio;
  316.   Boolean      saynum;
  317.   Boolean      help;
  318.   String       btnTextureFn; 
  319.   String       baseTextureFn; 
  320.   String       clickSndFn; 
  321.   String       growSndFn; 
  322.   String       roundBtnFn; 
  323.   String       roundBaseFn; 
  324.   String       sgiBtnFn; 
  325.   String       baseCol; 
  326.   String       digitBtnCol;
  327.   String       dispCol;
  328.   String       funcBtnCol;
  329. } appResources;
  330.  
  331.  
  332. #define offset(field) XtOffsetOf(struct resources, field)
  333. static XtResource Resources[] = {
  334.   { "baseCol",         "baseCol",          XtRString,     sizeof(String),
  335.      offset(baseCol),       XmRString,  NULL },
  336.   { "digitBtnCol",     "digitBtnCol",          XtRString,     sizeof(String),
  337.      offset(digitBtnCol),       XmRString,  NULL },
  338.   { "funcBtnCol",         "funcBtnCol",          XtRString,     sizeof(String),
  339.      offset(funcBtnCol),       XmRString,  NULL },
  340.   { "dispCol",         "dispCol",          XtRString,     sizeof(String),
  341.      offset(dispCol),       XmRString,  NULL },
  342.   { "btnTextureFn",    "BtnTextureFn",          XtRString,     sizeof(String),
  343.      offset(btnTextureFn),       XmRString,  NULL },
  344.   { "baseTextureFn",  "BaseTextureFn",          XtRString,     sizeof(String),
  345.      offset(baseTextureFn),       XmRString,  NULL },
  346.   { "clickSndFn",  "clickSndFn",          XtRString,     sizeof(String),
  347.      offset(clickSndFn),       XmRString,  NULL },
  348.   { "growSndFn",  "growSndFn",          XtRString,     sizeof(String),
  349.      offset(growSndFn),       XmRString,  NULL },
  350.   { "roundBtnFn",  "roundBtnFn",          XtRString,     sizeof(String),
  351.      offset(roundBtnFn),       XmRString,  NULL },
  352.   { "roundBaseFn",  "roundBaseFn",          XtRString,     sizeof(String),
  353.      offset(roundBaseFn),       XmRString,  NULL },
  354.   { "sgiBtnFn",  "sgiBtnFn",          XtRString,     sizeof(String),
  355.      offset(sgiBtnFn),       XmRString,  NULL },
  356.   {"maxWhizzy", "MaxWhizzy", XtRBoolean, sizeof(Boolean),
  357.      offset(maxWhizzy), XtRString, "False"},
  358.   {"niceBase", "NiceBase", XtRBoolean, sizeof(Boolean),
  359.      offset(niceBase), XtRString, "True"},
  360.   {"niceBtns", "NiceBtns", XtRBoolean, sizeof(Boolean),
  361.      offset(niceBtns), XtRString, "False"},
  362.   {"highlight", "highlight", XtRBoolean, sizeof(Boolean),
  363.      offset(highlight), XtRString, "False"},
  364.   {"kbdAnimate", "kbdAnimate", XtRBoolean, sizeof(Boolean),
  365.      offset(kbdAnimate), XtRString, "False"},
  366.   {"thickText", "ThickText", XtRBoolean, sizeof(Boolean),
  367.      offset(thickText), XtRString, "False"},
  368.   {"audio", "audio", XtRBoolean, sizeof(Boolean),
  369.      offset(audio), XtRString, "False"},
  370.   {"saynum", "saynum", XtRBoolean, sizeof(Boolean),
  371.      offset(saynum), XtRString, "False"},
  372.   {"textures", "Textures", XtRBoolean, sizeof(Boolean),
  373.      offset(textures), XtRString, "False"},
  374.   {"outputFile", "OutputFile", XtRBoolean, sizeof(Boolean),
  375.      offset(outputFile), XtRString, "False"},
  376.   {"help", "Help", XtRBoolean, sizeof(Boolean),
  377.      offset(help), XtRString, "False"}
  378. };
  379. #undef offset
  380.  
  381.  
  382. static XrmOptionDescRec optionDesc[] = {
  383.   { "-maxWhizzy",    "maxWhizzy",    XrmoptionNoArg,  (caddr_t) "True" },
  384.   { "-niceBtns",     "niceBtns",     XrmoptionNoArg,  (caddr_t) "True" },
  385.   { "-niceBase",     "niceBase",     XrmoptionNoArg,  (caddr_t) "True" },
  386.   { "-textures",     "textures",     XrmoptionNoArg,  (caddr_t) "True" },
  387.   { "-outputFile",   "outputFile",   XrmoptionNoArg,  (caddr_t) "True" },
  388.   { "-thickText",    "thickText",    XrmoptionNoArg,  (caddr_t) "True" },
  389.   { "-audio",        "audio",        XrmoptionNoArg,  (caddr_t) "True" },
  390.   { "-kbdAnimate",   "kbdAnimate",   XrmoptionNoArg,  (caddr_t) "True" },
  391.   { "-highlight",   "highlight",   XrmoptionNoArg,  (caddr_t) "True" },
  392.   { "-help",         "help",         XrmoptionNoArg,  (caddr_t) "True"}};
  393.  
  394.  
  395.  
  396. static String fallbackResources[] = {
  397.   "*digitBtnCol:              0.25 0.26 0.09",
  398.   "*funcBtnCol:               0.00 0.26 0.60",
  399.   "*baseCol:                  0.67 0.35 0.00",
  400.   "*dispCol:                  0.59 0.59 0.59",
  401.   "*btnTextureFn:             corinth.rgb",
  402.   "*baseTextureFn:            redmar.rgb",
  403.   "*clickSndFn:               drm_clave.aiff",
  404.   "*growSndFn:                belltree_up2.aiff",
  405.   "*roundBtnFn:               cbutton.iv",
  406.   "*roundBaseFn:              cbase.iv",
  407.   "*sgiBtnFn:                 sgigrow.iv",
  408.   "*sgiMode: True",
  409.   "*useSchemes: all", 
  410.   NULL 
  411. };
  412.  
  413.  
  414.  
  415. class TextReg {
  416.  
  417.   char *dispStr;
  418.   double number;
  419.   char tmp[32];
  420.  
  421.  public:
  422.   TextReg(char *str)
  423.     {
  424.       dispStr = new(char [80]);
  425.       setValue( str );      
  426.     }
  427.  
  428.   void clear()
  429.     {
  430.       number = 0.0;
  431.       *dispStr = '\0';
  432.     }
  433.  
  434.  
  435.   void addChar(char ch)
  436.     {
  437.      int sLen = strlen(dispStr);
  438.      if ( sLen != MAXDISP ) {
  439.        dispStr[sLen] = ch;
  440.        dispStr[sLen + 1] = '\0';
  441.      }
  442.     }
  443.  
  444.  
  445.   int getLength() { return( strlen( dispStr ));  }
  446.  
  447.   void setValue( char *str ) { strcpy( dispStr, str );  }  
  448.  
  449.   char * getValue() {  return( dispStr );  }  
  450.  
  451.   char getChar( int index )  {  return( dispStr[index] );  }
  452.  
  453.   void removeHead()  { strcpy( dispStr, dispStr + 1 );   }
  454.  
  455.   void addHead( char ch )
  456.     {
  457.       sprintf( tmp, "%c%s", ch, dispStr );
  458.       strcpy( dispStr, tmp );
  459.     }
  460.  
  461.   void removeTail()  { dispStr[strlen(dispStr)-1] = '\0'; }
  462.   void replaceChar( int index, char ch )  {  dispStr[index] = ch;   }  
  463.  
  464.   void display( SoText3 *text )  {  text->string.setValue( dispStr ); }
  465. };
  466.  
  467.  
  468. Dim baseDim = { 640, 800, 80 };
  469. Dim dispDim = { 530, 125, 10 };
  470. Dim btnDim = { 100, 100, 20 };
  471. Dim keypadDim;
  472. Dim textDim = { 100, 100, 20 };
  473. Pos basePos = { 0, 0, 0 };
  474. Pos dispPos;
  475. Pos ansPos;
  476. Pos keypadPos;
  477. float xSpacing = 0;
  478. float ySpacing = 0;
  479. int numBtns;
  480. char dispStr[80];
  481. TextReg textReg( "0." );
  482. const float dispFontSize = 0.5 * dispDim.height;
  483. const float btnFontScale = 0.5;
  484. SoText3 *textDisp;
  485. Bool stillPushing = FALSE;
  486. Bool stillGrowing = FALSE;
  487. SoXtExaminerViewer *viewer;
  488. XtAppContext appContext;
  489. PickData pickData;
  490. float textThickness; 
  491. int numBasicBtns = 20;
  492. int numXtraBtns = 20;
  493.  
  494. ALport audioport;
  495.  
  496. static void usage();
  497. static void handlePickCB( void *, SoEventCallback * );
  498. static void handleKbdCB( void *, SoEventCallback * );
  499. static void btnAnimationCB( void *, SoSensor * );
  500. static void growCalcCB( void *, SoSensor * );
  501. static void initAppAndResources( int *, char **, Widget & );
  502. static void buildBtns( SoGroup *, PickData & );
  503. static SoSeparator * buildButton( int, SoMaterial *, SoFont *, SoTranslation *,
  504.                                  SoTexture2 *, SoNode * );
  505. static SoSeparator * buildBase();
  506. static SoSeparator * buildDisplay();
  507. static void printPath( const SoPath * );
  508. static void activateBtn( PickData * );
  509.  
  510. static void playSoundFn( char * );
  511. static void playSnd( void * );
  512. static void audioInit();
  513.  
  514.  
  515.  
  516.  
  517. main( int argc, char **argv )
  518. {
  519.   Widget appWindow;
  520.   initAppAndResources( &argc, argv, appWindow );
  521.   
  522.   SoSeparator *root = new SoSeparator;
  523.   SoPerspectiveCamera *camera = new SoPerspectiveCamera;
  524.   root->ref();
  525.   root->addChild( camera );
  526.   pickData.camera = camera;
  527.  
  528.   SoTransform *xform = new SoTransform;
  529.   xform->rotation.setValue( SbVec3f( 1, 0, 0 ), -M_PI/6 );
  530.   root->addChild(xform);
  531.   
  532.   SoEventCallback *eventCB = new SoEventCallback;
  533.   root->addChild( eventCB );
  534.   
  535.   SoSeparator *calcBaseGroup = new SoSeparator;
  536.   calcBaseGroup->addChild( buildBase() );
  537.   calcBaseGroup->addChild( buildDisplay() );
  538.   
  539.   root->addChild( calcBaseGroup );
  540.  
  541.   pickData.grow = False;
  542.   pickData.root = root;
  543.   buildBtns(calcBaseGroup, pickData);
  544.   
  545.   viewer = new SoXtExaminerViewer( appWindow );
  546.   viewer->setSceneGraph( root );
  547.   viewer->setTitle( "IVcalc" );
  548.   viewer->setIconTitle( "IVcalc" );
  549.   viewer->setSize( SbVec2s( 300, 350 ));
  550.   viewer->setViewing( FALSE );
  551.   viewer->setDecoration( FALSE );
  552.   
  553.   pickData.vp = viewer->getViewportRegion();
  554.   camera->viewAll( root, pickData.vp );
  555.   camera->position.setValue( 0, 0, 1100 );
  556.     
  557.   viewer->show();
  558.     
  559.   SbVec2s winSize = viewer->getSize();
  560.   pickData.root = root;
  561.  
  562.   eventCB->addEventCallback( SoMouseButtonEvent::getClassTypeId(),
  563.                  handlePickCB, &pickData );
  564.  
  565.   eventCB->addEventCallback( SoKeyboardEvent::getClassTypeId(),
  566.                   handleKbdCB, &pickData );
  567.  
  568.   if ( appResources.outputFile ) {
  569.     SoOutput *outfile = new SoOutput;
  570.     if ( outfile->openFile( "calc.iv" ))  {
  571.       SoWriteAction *writeAction = new SoWriteAction( outfile );
  572.       writeAction->apply( root );
  573.      }
  574.   }
  575.      
  576.   if ( appResources.audio )
  577.     audioInit();
  578.  
  579.   SoXt::show( appWindow );  // Display main window
  580.   SoXt::mainLoop();         // Main Inventor event loop
  581. }
  582.  
  583.  
  584.  
  585. static void
  586. initAppAndResources( int *argc, char **argv, Widget &appWindow )
  587. {
  588. #ifdef SYSTYPE_SVR4
  589.   int *avalue = argc;
  590. #else
  591.   Cardinal *avalue = (Cardinal *)argc;
  592. #endif
  593.  
  594.    appWindow = XtVaAppInitialize( &appContext, "IVcalc",
  595.                     optionDesc, XtNumber(optionDesc),
  596.                     avalue, argv,
  597.                     fallbackResources,
  598.                     NULL);   
  599.  
  600.    if ( *argc > 1 )
  601.      usage();
  602.  
  603.    SoXt::init( appWindow ); // pass top Level widget
  604.    if ( appWindow == NULL ) exit( 1 );
  605.  
  606.    
  607.    XtGetApplicationResources(appWindow, (XtPointer)&appResources, Resources,
  608.                  XtNumber(Resources), (ArgList) NULL, NULL);
  609.  
  610.    if ( appResources.help )
  611.       usage();
  612.  
  613.    sscanf(appResources.digitBtnCol, "%f %f %f", &calcCols[0].r, &calcCols[0].g,
  614.       &calcCols[0].b );
  615.    sscanf( appResources.funcBtnCol, "%f %f %f", &calcCols[1].r, &calcCols[1].g,
  616.       &calcCols[1].b );
  617.    sscanf( appResources.baseCol, "%f %f %f", &calcCols[2].r, &calcCols[2].g,
  618.       &calcCols[2].b );
  619.    sscanf( appResources.dispCol, "%f %f %f", &calcCols[3].r, &calcCols[3].g,
  620.       &calcCols[3].b );
  621.  
  622.    if ( appResources.maxWhizzy || appResources.thickText )
  623.        textThickness = TEXTDEPTH;
  624.      else 
  625.        textThickness = 1.0;
  626. }
  627.  
  628.  
  629.  
  630. static SoSeparator * 
  631. buildDisplay()
  632. {
  633.   SoSeparator *calcDisp = new SoSeparator;
  634.  
  635.   SoMaterial *mtlDisp = new SoMaterial;
  636.   mtlDisp->diffuseColor.setValue( calcCols[3].r, calcCols[3].g, 
  637.                   calcCols[3].b );  
  638.   calcDisp->addChild( mtlDisp );
  639.  
  640.   SoTranslation *xlateDisp = new SoTranslation;
  641.   calcDisp->addChild( xlateDisp );
  642.  
  643.   SoCube *answerDisplay = new SoCube;
  644.   answerDisplay->width = dispDim.width;
  645.   answerDisplay->height = dispDim.height;
  646.   answerDisplay->depth = dispDim.depth;
  647.   calcDisp->addChild( answerDisplay );
  648.  
  649.   dispPos.x = 0;
  650.   dispPos.y = baseDim.height / 2 - dispDim.height / 2 - baseDim.height * 0.05;
  651.   dispPos.z = ( baseDim.depth / 2 ) + ( dispDim.depth / 2 );
  652.   xlateDisp->translation.setValue(SbVec3f( dispPos.x, dispPos.y, dispPos.z ));
  653.  
  654.   SoSeparator *ansText = new SoSeparator;
  655.  
  656.   SoPickStyle *pickStyle = new SoPickStyle;
  657.   pickStyle->style.setValue( SoPickStyle::UNPICKABLE );
  658.   ansText->addChild( pickStyle );
  659.   
  660.   SoMaterial *mtlText = new SoMaterial;
  661.   mtlText->diffuseColor.setValue( 0.0, 0.0, 0.0 );
  662.   ansText->addChild( mtlText );
  663.   
  664.   SoFont *font = new SoFont;
  665.   font->name.setValue( "Utopia-Bold" );
  666.   font->size = dispFontSize;
  667.   ansText->addChild( font );
  668.   SoTranslation *xlateText = new SoTranslation;
  669.   ansText->addChild( xlateText );
  670.   
  671.   textDisp = new SoText3;
  672.   
  673.   if ( appResources.maxWhizzy || appResources.thickText )
  674.     textDisp->parts.setValue( SoText3::FRONT | SoText3::SIDES );
  675.   else
  676.     textDisp->parts.setValue( SoText3::FRONT );
  677.   
  678.   SoScale *scaleText = new SoScale;
  679.   scaleText->scaleFactor.setValue( SbVec3f( 1.0, 1.6, textThickness ));
  680.   ansText->addChild( scaleText );
  681.  
  682.   textDisp->justification.setValue( SoText3::RIGHT );
  683.   textReg.display( textDisp );
  684.   ansText->addChild( textDisp );
  685.   calcDisp->addChild( ansText );
  686.   
  687. //  const SbViewportRegion &vp  = viewer->getViewportRegion();
  688.   SoGetBoundingBoxAction *bboxAction = new SoGetBoundingBoxAction( pickData.vp );
  689.   bboxAction->apply( ansText );
  690.   bboxAction->getBoundingBox().getSize( textDim.width, textDim.height, 
  691.                        textDim.depth );
  692.   ansPos.x = ( dispDim.width / 2 ) * 0.9;
  693.   ansPos.y = -textDim.height / 2;
  694.   ansPos.z = ( dispDim.depth / 2 ) + ( textDim.depth / 2 ) + textThickness;
  695.   xlateText->translation.setValue(SbVec3f( ansPos.x, ansPos.y , ansPos.z ));
  696.   
  697.   return( calcDisp );
  698. }
  699.  
  700.  
  701. static SoSeparator * 
  702. buildBase()
  703. {
  704.    SoSeparator *calcBase = new SoSeparator;
  705.  
  706.    SoTransform *xform = new SoTransform;
  707.    calcBase->addChild(xform);
  708.    pickData.xformBase = xform;
  709.  
  710.    SoMaterial *mtlBase = new SoMaterial;
  711.    mtlBase->diffuseColor.setValue( calcCols[2].r, calcCols[2].g, 
  712.                   calcCols[2].b ); 
  713.    mtlBase->specularColor.setValue(.6, .6, .6);
  714.    mtlBase->shininess.setValue(.5);
  715.    calcBase->addChild( mtlBase );
  716.  
  717.    SoTexture2 *baseTxtr;
  718.    if ( appResources.maxWhizzy || appResources.textures ) {
  719.      baseTxtr = new SoTexture2;
  720.      baseTxtr->filename.setValue( appResources.baseTextureFn );
  721.      baseTxtr->model.setValue( SoTexture2::MODULATE );
  722.      calcBase->addChild( baseTxtr );
  723.    }
  724.  
  725.    SoNode *baseShape;
  726.    if ( appResources.maxWhizzy || appResources.niceBase ) {
  727.      SoInput myfile;
  728.      myfile.openFile( appResources.roundBaseFn );
  729.      SoDB::read( &myfile, baseShape );
  730.    }
  731.    else {
  732.      baseShape = new SoCube;
  733.      ((SoCube *)baseShape)->width = baseDim.width;
  734.      ((SoCube *)baseShape)->height = baseDim.height;
  735.      ((SoCube *)baseShape)->depth = baseDim.depth;
  736.    }
  737.    calcBase->addChild( baseShape );
  738.    return( calcBase );
  739. }
  740.  
  741.  
  742. static void 
  743. buildBtns( SoGroup *calcBase, PickData &pickData )
  744. {
  745.    SoSeparator *keypad = new SoSeparator;
  746.    SoNode *tmpBtn;
  747.    SoTexture2 *texture;
  748.  
  749.    if ( appResources.maxWhizzy || appResources.niceBtns ) {
  750.      SoInput myfile;
  751.      myfile.openFile( appResources.roundBtnFn );
  752.      SoDB::read( &myfile, tmpBtn );
  753.    }
  754.    else {
  755.      tmpBtn = new SoCube;
  756.      ((SoCube *)tmpBtn)->width = btnDim.width;
  757.      ((SoCube *)tmpBtn)->height = btnDim.height;
  758.      ((SoCube *)tmpBtn)->depth = btnDim.depth;
  759.    }
  760.    
  761.    xSpacing = BTNSLOP * btnDim.width;
  762.    ySpacing = BTNSLOP * btnDim.height;
  763.  
  764.    SoTranslation *xlateBtns = new SoTranslation;
  765.  
  766.    keypadDim.width = NUMCOLS * btnDim.width - (( NUMCOLS - 1 ) * xSpacing );
  767.    keypadPos.x = ( baseDim.width - ( NUMCOLS * btnDim.width ) - 
  768.                 (( NUMCOLS - 1 ) * xSpacing )) / 2 - ( baseDim.width / 2 ) +
  769.                  ( btnDim.width / 2 );
  770.    keypadDim.height = NUMROWS * btnDim.height  - (( NUMROWS - 1 ) * ySpacing);
  771.    float offsetFromDisp = dispPos.y - dispDim.height / 2;
  772.    keypadPos.y = ( keypadDim.height / 2 ) - ( baseDim.height * 0.05 );
  773.    keypadPos.z = baseDim.depth / 2 + btnDim.depth / 2;
  774.  
  775.    xlateBtns->translation.setValue(SbVec3f( keypadPos.x, keypadPos.y, 
  776.                        keypadPos.z ));
  777.    keypad->addChild( xlateBtns );
  778.    pickData.xlateKeypad = xlateBtns;
  779.  
  780.    if ( appResources.maxWhizzy || appResources.textures ) {
  781.      texture = new SoTexture2;
  782.      texture->filename.setValue( appResources.btnTextureFn );
  783.      texture->model.setValue( SoTexture2::MODULATE );
  784.    }
  785.  
  786.    SoSeparator *nodeText = new SoSeparator;
  787.    SoMaterial *mtlText = new SoMaterial;
  788.    mtlText->diffuseColor.setValue( 1.0, 1.0, 1.0 );   // white
  789.  
  790.    SoFont *font = new SoFont;
  791.    font->name.setValue( "Utopia-Bold" );
  792.    float btnFontSize = btnDim.height * btnFontScale;
  793.    font->size = btnFontSize;
  794.  
  795.  
  796.    SoTranslation *xlateText = new SoTranslation;
  797.    xlateText->translation.setValue( SbVec3f( 0, -btnFontSize / 2,
  798.                         btnDim.depth/2 + textThickness  ));
  799.  
  800.    SoSwitch *basicBtns = new SoSwitch;
  801.    for ( int i = 0; i < numBasicBtns; i++ )
  802.      basicBtns->addChild( buildButton( i, mtlText, font, xlateText, texture,
  803.                    tmpBtn ));
  804.    basicBtns->whichChild.setValue( SO_SWITCH_ALL );
  805.  
  806.    SoSwitch *xtraBtns = new SoSwitch;
  807.    for ( i = numBasicBtns; i < numBasicBtns + numXtraBtns; i++ ) 
  808.      xtraBtns->addChild( buildButton( i, mtlText, font, xlateText, texture,
  809.                    tmpBtn ));
  810.    xtraBtns->whichChild.setValue( SO_SWITCH_NONE );
  811.    pickData.xtraBtns = xtraBtns;
  812.    
  813.    numBtns = numBasicBtns + numXtraBtns;
  814.    keypad->addChild( basicBtns );
  815.    keypad->addChild( xtraBtns );
  816.    calcBase->addChild( keypad );
  817. }
  818.  
  819.  
  820.  
  821. static SoSeparator *
  822. buildButton( int i, SoMaterial *mtlText, SoFont *font,
  823.         SoTranslation *xlateText, SoTexture2 *texture, SoNode *tmpBtn )
  824. {
  825.   SoSeparator *groupBtn = new SoSeparator;
  826.   SoSeparator *compBtn = new SoSeparator;
  827.   SoNode *tmpLabel;
  828.  
  829.  
  830.   SoInput myfile;
  831.   myfile.openFile( appResources.sgiBtnFn );
  832.   SoDB::read( &myfile, tmpLabel );
  833.  
  834.   SoTranslation *xlateBtn = new SoTranslation;
  835.   xlateBtn->translation.setValue( SbVec3f( colOff[ btns[ i ].x ], 
  836.                       rowOff[ btns[ i ].y ],
  837.                       btns[i].z));
  838.   
  839.   SoLabel *labelBtn = new SoLabel;
  840.   labelBtn->label = btns[i].label;
  841.  
  842.   SoMaterial *mtlBtn = new SoMaterial;
  843.   mtlBtn->diffuseColor.setValue( calcCols[ btns[ i ].colIndex ].r,
  844.                 calcCols[ btns[ i ].colIndex ].g,
  845.                 calcCols[ btns[ i ].colIndex ].b );
  846.   pickData.mtlBtn = mtlBtn;
  847.   mtlBtn->specularColor.setValue(.6, .6, .6);
  848.   mtlBtn->shininess.setValue(.5);
  849.   SoText3 *text = new SoText3;
  850.   if ( appResources.maxWhizzy || appResources.thickText ) 
  851.     text->parts.setValue( SoText3::FRONT | SoText3::SIDES );
  852.   else 
  853.     text->parts.setValue( SoText3::FRONT );
  854.   
  855.   SoScale *scaleText = new SoScale;
  856.   scaleText->scaleFactor.setValue( SbVec3f( 1.0, 1.5, textThickness ));
  857.  
  858.   SoPickStyle *pickStyle = new SoPickStyle;
  859.   pickStyle->style.setValue( SoPickStyle::UNPICKABLE );
  860.   
  861.   text->justification.setValue( SoText3::CENTER );
  862.   text->string.setValue( btns[i].label );
  863.   SoSeparator *textBtn = new SoSeparator;
  864.   textBtn->addChild( pickStyle );  
  865.   textBtn->addChild( mtlText );
  866.   textBtn->addChild( font );
  867.   textBtn->addChild( xlateText );
  868.   if ( strncmp( btns[i].label, "G", 1 )) {
  869.     textBtn->addChild( scaleText );
  870.     textBtn->addChild( text );
  871.   }
  872.   else {
  873.     SoTranslation *transLogo = new SoTranslation;
  874.     transLogo->translation.setValue( SbVec3f( -15, 35, 0 ));
  875.     textBtn->addChild( transLogo );
  876.     textBtn->addChild( tmpLabel );
  877.   }
  878.     
  879.   compBtn->renderCaching.setValue( SoSeparator::ON );
  880.   compBtn->addChild( labelBtn );
  881.   compBtn->addChild( mtlBtn );
  882.   compBtn->addChild( textBtn );
  883.   if ( appResources.maxWhizzy || appResources.textures ) 
  884.     compBtn->addChild( texture );
  885.   compBtn->addChild( tmpBtn );
  886.   groupBtn->addChild( xlateBtn );
  887.   groupBtn->addChild( compBtn );
  888.   btns[i].bOrigin = groupBtn;
  889.   return( groupBtn );
  890. }
  891.  
  892.  
  893.  
  894. static void
  895. usage()
  896. {
  897.   static char *help_message[] = {
  898.     "where options include:",
  899.     "    -niceBtns   rounded buttons",
  900.     "    -textures   apply textures to buttons and base",
  901.     "    -outputFile write out Inventor scenegraph to calc.iv",
  902.     "    -thickText  3D text with exagerated depth",
  903.     "    -audio      button sounds, etc",
  904.     "    -kbdAnimate buttons are animated when kbd input used",
  905.     "    -maxWhizzy  turn on all extra enhancements (except kbdAnimate)",
  906.     "    -help       print this usage message",
  907.     NULL};
  908.   char **s;
  909.   
  910.   cout << "usage:\t  [-options ...]" << endl;
  911.   for (s= help_message; *s; s++)
  912.     cout << *s << endl;
  913.   cout << endl;
  914.   exit(0);
  915. }
  916.  
  917.  
  918. static void 
  919. handlePickCB(void *userData, SoEventCallback *eventCB)
  920. {
  921.   static Boolean firstCh = True;
  922.   PickData *pickData = (PickData *) userData;
  923.   
  924.   const SoEvent *event = eventCB->getEvent();
  925.   if ( SO_MOUSE_PRESS_EVENT( event, BUTTON1 )) { 
  926.     const SoPickedPoint *ePP = eventCB->getPickedPoint();
  927.     if ( ePP == NULL ) 
  928.       return;
  929.     const SoPath *ePath = ePP->getPath();
  930.     if ( ePath == NULL )
  931.       return;
  932.     for ( int i = 0; i < numBtns; i++ ) {
  933.       if ( ePath->containsNode( btns[i].bOrigin )) {      
  934.         if ( stillPushing )
  935.           return;
  936.         eventCB->setHandled();
  937.         pickData->activateType = ANIMATE;
  938.         pickData->btnIndex = i;
  939.           activateBtn( pickData );
  940.           break;
  941.       }
  942.     }
  943.   }
  944. }
  945.  
  946.  
  947.  
  948. static void 
  949. handleKbdCB(void *userData, SoEventCallback *eventCB)
  950. {
  951.   PickData *pickData = (PickData *) userData;
  952.   int keyTag;
  953.   static Boolean shiftFlag = False;
  954.   const SoKeyboardEvent *event = (SoKeyboardEvent *)eventCB->getEvent();
  955.  
  956. // set and unset shiftFlag to denote shift key usage and 
  957. // throw away initail presses of keys and only act on the release of other keys
  958.   if ( event->isKeyPressEvent( event, SoKeyboardEvent::LEFT_SHIFT ) ||
  959.        event->isKeyPressEvent( event, SoKeyboardEvent::RIGHT_SHIFT )) {
  960.     shiftFlag = True;
  961.     eventCB->setHandled();
  962.     return;
  963.   }
  964.   else if ( event->isKeyReleaseEvent( event, SoKeyboardEvent::LEFT_SHIFT ) ||
  965.        event->isKeyReleaseEvent( event, SoKeyboardEvent::RIGHT_SHIFT )) {
  966.     shiftFlag = False;
  967.     eventCB->setHandled();
  968.     return;
  969.   }
  970.   else if ( event->isKeyPressEvent( event, SoKeyboardEvent::ANY )) {
  971.     eventCB->setHandled();
  972.     return;
  973.   }
  974.   else if ( event->isKeyReleaseEvent( event, SoKeyboardEvent::ANY )) 
  975.     eventCB->setHandled(); 
  976.  
  977.     
  978.   switch ( event->getKey() ) {
  979.   case SoKeyboardEvent::PAD_0:
  980.   case SoKeyboardEvent::NUMBER_0: { keyTag = kZERO; break; }
  981.   case SoKeyboardEvent::PAD_1:
  982.   case SoKeyboardEvent::NUMBER_1: { keyTag = kONE; break; }
  983.   case SoKeyboardEvent::PAD_2:
  984.   case SoKeyboardEvent::NUMBER_2: { keyTag = kTWO; break; }
  985.   case SoKeyboardEvent::PAD_3:
  986.   case SoKeyboardEvent::NUMBER_3: { keyTag = kTHREE; break; }
  987.   case SoKeyboardEvent::PAD_4:
  988.   case SoKeyboardEvent::NUMBER_4: { keyTag = kFOUR; break; }
  989.   case SoKeyboardEvent::PAD_5:
  990.   case SoKeyboardEvent::NUMBER_5: { keyTag = kFIVE; break; }
  991.   case SoKeyboardEvent::PAD_6:
  992.   case SoKeyboardEvent::NUMBER_6: { keyTag = kSIX; break; }
  993.   case SoKeyboardEvent::PAD_7:
  994.   case SoKeyboardEvent::NUMBER_7: { keyTag = kSEVEN; break; }
  995.   case SoKeyboardEvent::PAD_8:
  996.   case SoKeyboardEvent::NUMBER_8: { if ( shiftFlag )
  997.                       keyTag = kMUL;
  998.                     else
  999.                       keyTag = kEIGHT; break; }
  1000.   case SoKeyboardEvent::PAD_9:
  1001.   case SoKeyboardEvent::NUMBER_9: { keyTag = kNINE; break; }
  1002.   case SoKeyboardEvent::PAD_ADD: { keyTag = kADD; break; }
  1003.   case SoKeyboardEvent::PAD_SUBTRACT:
  1004.   case SoKeyboardEvent::MINUS: { keyTag = kSUB; break; }
  1005.   case SoKeyboardEvent::PAD_MULTIPLY: { keyTag = kMUL; break; }
  1006.   case SoKeyboardEvent::PAD_DIVIDE:
  1007.   case SoKeyboardEvent::SLASH: { keyTag = kDIV; break; }
  1008.   case SoKeyboardEvent::EQUAL: { if ( shiftFlag )
  1009.                       keyTag = kADD;
  1010.                     else
  1011.                       keyTag = kEQU; break; }
  1012.   case SoKeyboardEvent::PAD_ENTER:
  1013.   case SoKeyboardEvent::ENTER: { keyTag = kEQU; break; }
  1014.   case SoKeyboardEvent::PAD_PERIOD:
  1015.   case SoKeyboardEvent::PERIOD: { keyTag = kDEC; break; }
  1016.   case SoKeyboardEvent::BACKSPACE:
  1017.   case SoKeyboardEvent::DELETE: { keyTag = kBKSP; break; } 
  1018.   case SoKeyboardEvent::C: { keyTag = kCLR; break; }
  1019.   case SoKeyboardEvent::Q: { Quit(); break; }
  1020.   }
  1021.   
  1022.   for ( int i = 0; i < numBtns; i++ ) {
  1023.     if ( keyTag == btns[i].btnVal ) {      
  1024.       if ( appResources.maxWhizzy || appResources.audio )
  1025.     playSoundFn( appResources.clickSndFn );
  1026.  
  1027.       if ( stillPushing )
  1028.     return;
  1029.       if ( appResources.kbdAnimate )
  1030.     pickData->activateType = ANIMATE;
  1031.       else
  1032.     pickData->activateType = HIGHLIGHT;
  1033.       pickData->btnIndex = i;
  1034.       activateBtn( pickData );
  1035.       break;
  1036.     }
  1037.   }
  1038. }
  1039.  
  1040.  
  1041.  
  1042.  
  1043. static void
  1044. activateBtn( PickData *pickData )
  1045. {
  1046.   static SoTimerSensor *timer = new SoTimerSensor( btnAnimationCB, pickData );
  1047.  
  1048.   SoSeparator *topNode = btns[pickData->btnIndex].bOrigin;
  1049.   for (int j = 0; j < topNode->getNumChildren(); j++) {
  1050.     if ( topNode->getChild( j )->getTypeId() == 
  1051.       SoTranslation::getClassTypeId())
  1052.       pickData->xlateBtn = (SoTranslation *)topNode->getChild( j );
  1053.   }
  1054.  
  1055.   btns[pickData->btnIndex].func( btns[pickData->btnIndex].btnVal );
  1056.  
  1057.   if ( pickData->activateType == ANIMATE || appResources.highlight ) {
  1058.     timer->setInterval( TIMERFREQ );  // timer to go off every 1/10 sec
  1059.     timer->schedule();
  1060.   }
  1061.   else
  1062.     textReg.display( textDisp );
  1063. }
  1064.  
  1065.  
  1066.  
  1067. static void
  1068. printPath(const SoPath *path)
  1069. {
  1070.   for ( int i = 0; i < path->getLength(); i++ )
  1071.      cout << path->getNode( i )->getTypeId().getName().getString() << endl; 
  1072. }
  1073.  
  1074.  
  1075.  
  1076. static void
  1077. growCalc( int )
  1078. {
  1079.   static SoTimerSensor *timer = new SoTimerSensor( growCalcCB, &pickData );
  1080.  
  1081.   if ( stillGrowing )
  1082.     return; 
  1083.  
  1084.   stillGrowing = True;
  1085.  
  1086.   if ( pickData.grow ) {
  1087.     pickData.grow = False;
  1088.     pickData.xtraBtns->whichChild.setValue( SO_SWITCH_NONE );
  1089.   }
  1090.   else {
  1091.     pickData.grow = True;
  1092.     pickData.camera->viewAll( pickData.root, pickData.vp );   
  1093.   }
  1094.  
  1095.   if ( appResources.maxWhizzy || appResources.audio )
  1096.     playSoundFn( appResources.growSndFn );
  1097.  
  1098.   timer->setInterval( TIMERFREQ );  // timer to go off every 1/100 sec
  1099.   timer->schedule();
  1100. }
  1101.  
  1102.  
  1103.  
  1104. static void
  1105. growCalcCB( void *userData, SoSensor *sensor )
  1106. {
  1107.   const int ANIMTIMES = 10;
  1108.   PickData *pickData = (PickData *) userData;
  1109.   SoTimerSensor *timer = (SoTimerSensor *) sensor;
  1110.   static float scaleInc = ( NUMXTRACOLS * ( btnDim.width + 
  1111.                       ( BTNSLOP * btnDim.width ))
  1112.                   / baseDim.width ) / ANIMTIMES;
  1113.   static float growInc = ( scaleInc * baseDim.width ) / 2;
  1114.   static float scaleFactor;
  1115.   static int counter = 0;
  1116.  
  1117.  
  1118.   if ( ++counter < ANIMTIMES + 1 ) {
  1119.     if ( pickData->grow ) {
  1120.       scaleFactor =  1 + scaleInc * counter;
  1121.       keypadPos.x += growInc;
  1122.     }
  1123.     else {
  1124.       scaleFactor = 1 + (scaleInc * ANIMTIMES) - 
  1125.                 scaleInc * counter;
  1126.       keypadPos.x -= growInc;
  1127.     }
  1128.  
  1129.     pickData->xformBase->scaleFactor.setValue( SbVec3f( scaleFactor, 1, 1 ));
  1130.     pickData->xlateKeypad->translation.setValue(SbVec3f(keypadPos.x, 
  1131.                             keypadPos.y, 
  1132.                             keypadPos.z ));
  1133.     viewer->render();
  1134.   }
  1135.   else {
  1136.     if ( pickData->grow ) {
  1137.     pickData->xtraBtns->whichChild.setValue( SO_SWITCH_ALL );
  1138.     baseDim.width *= scaleFactor;
  1139.       }
  1140.     else {
  1141.       pickData->camera->viewAll( pickData->root, pickData->vp );   
  1142.       baseDim.width *= 1 / ( 1 + scaleInc * ANIMTIMES );
  1143.     }
  1144.     stillGrowing = False;
  1145.     counter = 0;
  1146.     timer->unschedule();
  1147.   }
  1148. }
  1149.  
  1150.  
  1151.  
  1152. static void
  1153. btnAnimationCB( void *userData, SoSensor *sensor)
  1154. {
  1155.   const int ANIMTIMES = 2;
  1156.   PickData *pickData = (PickData *) userData;
  1157.   SoTimerSensor *timer = (SoTimerSensor *) sensor;
  1158.   static SbVec3f curTrans;
  1159.   static int counter = ANIMTIMES;
  1160.   static Boolean isHighlighted = False;
  1161.   static SoTranslation *btnTrans = new SoTranslation;
  1162.  
  1163.   if ( pickData->activateType == HIGHLIGHT ) {
  1164.     if ( isHighlighted ) {
  1165.       isHighlighted = False;
  1166.       stillPushing = False;
  1167.       int i = pickData->btnIndex;
  1168.       pickData->mtlBtn->diffuseColor.setValue( calcCols[ btns[i].colIndex ].r,
  1169.                     calcCols[ btns[i].colIndex ].g,
  1170.                     calcCols[ btns[i].colIndex ].b );
  1171.       timer->unschedule();
  1172.     }
  1173.     else {
  1174.       isHighlighted = True;
  1175.       stillPushing = True;
  1176.       pickData->mtlBtn->diffuseColor.setValue( .8, 0, 0 );
  1177.     }
  1178.   }
  1179.  
  1180.     switch ( counter ) {
  1181.     case 0:
  1182.       timer->unschedule();
  1183.       counter = ANIMTIMES;
  1184.       stillPushing = FALSE;
  1185.       viewer->setAutoRedraw( TRUE );
  1186.       return;
  1187.     case 1:
  1188.       curTrans[2] = 0;
  1189.       counter--;
  1190.       if ( appResources.maxWhizzy || appResources.audio )
  1191.         playSoundFn( appResources.clickSndFn );
  1192.       textReg.display( textDisp );
  1193.       break;
  1194.     case ANIMTIMES:
  1195.       btnTrans = pickData->xlateBtn;
  1196.       curTrans = btnTrans->translation.getValue();
  1197.       stillPushing = TRUE;
  1198.       viewer->setAutoRedraw( FALSE );
  1199.     default: 
  1200.       curTrans[2] = -BTNDEPTH + 2;
  1201.       counter--;
  1202.       break;
  1203.     }
  1204.   
  1205.   btnTrans->translation.setValue( curTrans );
  1206.   viewer->render();
  1207. }
  1208.  
  1209.  
  1210.  
  1211. static void
  1212. audioInit()
  1213. {
  1214. }
  1215.  
  1216.  
  1217. static void
  1218. playSoundFn( char *sndfn )
  1219. {
  1220.   static char *playaifc = "playaifc ";
  1221.   static char *devnull = " > /dev/null";
  1222.   char playStr[ 80 ];
  1223.  
  1224.   strcpy( playStr, playaifc );
  1225.   strcat( playStr, sndfn );
  1226.   strcat( playStr, devnull );
  1227.  
  1228.   sproc( playSnd, PR_SALL, playStr );
  1229. }
  1230.  
  1231.  
  1232.  
  1233. static void
  1234. playSnd( void *playStr )
  1235. {
  1236.   system( (char *)playStr );
  1237. }
  1238.  
  1239.  
  1240.  
  1241. //  ****************************************
  1242. //  ******  xcalc code  ******
  1243. //  ****************************************
  1244.  
  1245. /* The following routines are based on code from the MIT X11 sample client
  1246.  * code for xcalc.
  1247.  * 
  1248.  * xcalc.c  -  a hand calculator for the X Window system
  1249.  * 
  1250.  * Copyright 1989 by the Massachusetts Institute of Technology
  1251.  */
  1252.  
  1253.  
  1254. static void
  1255. digit( int keynum )
  1256. {
  1257.   XCALC_PRE_OP( keynum );
  1258.   numeric( keynum );
  1259.   post_op();
  1260. }
  1261.  
  1262.  
  1263. static void
  1264. numeric( int keynum )
  1265. {
  1266.   if ( clrdisp ) {
  1267.     textReg.clear();
  1268.     exponent = Dpoint = 0;
  1269. //    if (rpn && entered==2)
  1270. //      PushNum(dnum);
  1271.     if (rpn & lift_enabled)
  1272.         PushNum(dnum);
  1273.   }
  1274.  
  1275.   if ( textReg.getLength() >= MAXDISP )
  1276.     return;
  1277.   
  1278.   switch ( keynum ) {
  1279.   case kONE:        textReg.addChar( '1' ); break;
  1280.   case kTWO:        textReg.addChar( '2' ); break;
  1281.   case kTHREE:      textReg.addChar( '3' ); break;
  1282.   case kFOUR:       textReg.addChar( '4' ); break;
  1283.   case kFIVE:       textReg.addChar( '5' ); break;
  1284.   case kSIX:        textReg.addChar( '6' ); break;
  1285.   case kSEVEN:      textReg.addChar( '7' ); break;
  1286.   case kEIGHT:      textReg.addChar( '8' ); break;
  1287.   case kNINE:       textReg.addChar( '9' ); break;
  1288.   case kZERO:       textReg.addChar( '0' ); break;
  1289.   }
  1290.   
  1291.   DrawDisplay();
  1292.   if ( clrdisp && keynum != kZERO )
  1293.     clrdisp = 0; /*no leading 0s*/
  1294.   entered = 1;
  1295.   lift_enabled = 0;
  1296. }
  1297.  
  1298.  
  1299. static void
  1300. post_op()
  1301. {
  1302.   if (errno) {
  1303.     textReg.setValue( "error" );
  1304.     DrawDisplay();
  1305.     entered=3;
  1306.     errno=0;
  1307.   }
  1308. }
  1309.  
  1310.  
  1311. static void
  1312. effectUpdate()
  1313. {
  1314.    textReg.display( textDisp );
  1315. }
  1316.  
  1317. static void
  1318. DrawDisplay()
  1319. {
  1320.   //display is updated in btnAnimationCB so as to try to have
  1321.   //the new numbers appear as the button reaches the bottom of its press
  1322. }
  1323.  
  1324.  
  1325. static void
  1326. twof( int )
  1327. {
  1328. }
  1329.  
  1330.  
  1331. static void
  1332. memf( int keynum )
  1333. {
  1334.     memop = keynum;
  1335.     char *tmpStr;
  1336.     if (entered==1) {
  1337.       tmpStr = textReg.getValue();
  1338.       parse_double( tmpStr, "%lf", &dnum );
  1339.     }
  1340.     entered = 2;
  1341.     clrdisp++;
  1342.     lift_enabled = 0;
  1343. }
  1344.  
  1345.  
  1346. static void
  1347. oneop( int keynum )
  1348. {
  1349.   int i,j;
  1350.   double dtmp;
  1351.  
  1352.   char *tmpStr = textReg.getValue();
  1353.   if (entered==1) {
  1354.     parse_double( tmpStr, "%lf", &dnum );
  1355.   }
  1356.   entered = 2;
  1357.  
  1358.   switch ( keynum ) {  /* do the actual math fn. */
  1359.   case kE:     if (rpn && memop != kENTR) PushNum(dnum); dnum=E;  break;
  1360.   case kPI:    if (rpn && memop != kENTR) PushNum(dnum); dnum=PI;  break;
  1361.   case kRECIP: dnum=1.0/dnum;  break;
  1362.   case kSQR:   flagINV = !flagINV; /* fall through to */
  1363.   case kSQRT:  if (flagINV) dnum=dnum*dnum;
  1364.                else dnum=sqrt(dnum);
  1365.                break;
  1366.   case k10X:   flagINV = !flagINV; /* fall through to */
  1367.   case kLOG:   if (flagINV) dnum=pow(10.0,dnum);
  1368.                else dnum=log10(dnum);
  1369.                break;
  1370.   case kEXP:   flagINV = !flagINV; /* fall through to */
  1371.   case kLN:    if (flagINV) dnum=exp(dnum);
  1372.                else dnum=log(dnum);
  1373.                break;
  1374.   case kSIN:   if (flagINV) dnum=asin(dnum)*rad2drg;
  1375.                else dnum=sin(dnum*drg2rad);
  1376.                break;
  1377.   case kCOS:   if (flagINV) dnum=acos(dnum)*rad2drg;
  1378.                else dnum=cos(dnum*drg2rad);
  1379.                break;
  1380.   case kTAN:   if (flagINV) dnum=atan(dnum)*rad2drg;
  1381.                else dnum=tan(dnum*drg2rad);
  1382.                break;
  1383.   case kSTO:   mem[0]=dnum;  flagM=!(mem[0]==0.0);  break;
  1384.   case kRCL:   if (rpn && lift_enabled) PushNum(dnum);
  1385.                dnum=mem[0];  flagM=!(mem[0]==0.0);  break;
  1386.   case kSUM:   mem[0]+=dnum; flagM=!(mem[0]==0.0);  break;
  1387.   case kEXC:   dtmp=dnum; dnum=mem[0];  mem[0]=dtmp;
  1388.                flagM=!(mem[0]==0.0);  break;
  1389.   case kFACT:  if (floor(dnum)!=dnum || dnum<0.0 || dnum>500.0) {
  1390.                  textReg.setValue( "stack error" );
  1391.                  entered=3;
  1392.                  break;
  1393.                }
  1394.                i=(int) (floor(dnum));
  1395.                for ( j = 1, dnum = 1.0; j <= i; j++ ) 
  1396.                  dnum *= (float) j;
  1397.                break;
  1398.   }
  1399.   
  1400.   if ( entered == 3 ) {  /* error */
  1401.     DrawDisplay();
  1402.     return;
  1403.   }
  1404.  
  1405.   entered=2;
  1406.   clrdisp=1;
  1407.   flagINV=0;
  1408.   lift_enabled = 1;
  1409.  
  1410.   sprintf( tmpStr, "%.8g", dnum );
  1411.   textReg.setValue( tmpStr );
  1412.   DrawDisplay();
  1413. }
  1414.  
  1415.  
  1416. static void
  1417. twoop( int keynum )
  1418. {
  1419.  
  1420.   if (flagINV) {
  1421.     flagINV=0;
  1422.     DrawDisplay();
  1423.   }
  1424.  
  1425.   if ( !entered ) {               /* something like "5+*" */
  1426.     if ( isopempty() == 0 )
  1427.       PopOp();                   /* replace the prev op */
  1428.     PushOp( keynum );             /* with the new one */
  1429.     return;
  1430.   }
  1431.  
  1432.   char *tmpStr;
  1433.   if (entered == 1) {
  1434.     tmpStr = textReg.getValue();
  1435.     parse_double( tmpStr,"%lf",&dnum );
  1436.   }
  1437.  
  1438.   clrdisp = CLR = 1;
  1439.   entered = Dpoint = exponent = 0;
  1440.  
  1441.   if ( isopempty() == 0 ) {  /* there was a previous op */
  1442.     lastop = PopOp();   /* get it */
  1443.  
  1444.     if ( lastop == kLPAR ) {  /* put it back */
  1445.       PushOp( kLPAR );
  1446.       PushOp( keynum );
  1447.       PushNum( dnum );
  1448.       return;
  1449.     }
  1450.  
  1451.     /* now, if the current op (keynum) is of
  1452.        higher priority than the lastop, the current
  1453.        op and number are just pushed on top 
  1454.        Priorities:  (Y^X) > *,/ > +,- */
  1455.     
  1456.     if (priority( keynum ) > priority( lastop )) {
  1457.       PushNum( dnum );
  1458.       PushOp( lastop );
  1459.       PushOp( keynum );
  1460.     } else {  /* execute lastop on lastnum and dnum, push
  1461.                result and current op on stack */
  1462.       acc = PopNum();
  1463.       switch ( lastop ) { /* perform the operation */
  1464.       case kADD: acc += dnum;  break;
  1465.       case kSUB: acc -= dnum;  break;
  1466.       case kMUL: acc *= dnum;  break;
  1467.       case kDIV: acc /= dnum;  break;
  1468.       case kPOW: acc =  pow(acc,dnum);  break;
  1469.         }
  1470.       PushNum( acc );
  1471.       PushOp( keynum );
  1472.       sprintf( tmpStr,"%.8g", acc);
  1473.       DrawDisplay();
  1474.       dnum=acc;
  1475.     }
  1476.   }
  1477.   else { /* op stack is empty, push op and num */
  1478.     PushOp( keynum );
  1479.     PushNum( dnum );
  1480.   } 
  1481. }                      
  1482.  
  1483.  
  1484.  
  1485. static void
  1486. PushOp( int op )
  1487. {
  1488.   if ( opsp == STACKMAX ) {
  1489.     textReg.setValue( "stack error" );
  1490.     entered=3;
  1491.   }
  1492.   else opstack[opsp++]=op;
  1493. }
  1494.  
  1495.  
  1496.  
  1497. static
  1498. int PopOp()
  1499. {
  1500.   if ( opsp == 0 ) {
  1501.       textReg.setValue( "stack error" );
  1502.       entered=3;
  1503.       return( kNOP );
  1504.   } else
  1505.     return( opstack[--opsp] );
  1506. }
  1507.  
  1508.  
  1509. static void
  1510. PushNum(double num)
  1511. {
  1512.   if ( rpn ) {
  1513.       numstack[2] = numstack[1];
  1514.       numstack[1] = numstack[0];
  1515.       numstack[0] = num;
  1516.       return;
  1517.   }
  1518.   if ( numsp == STACKMAX ) {
  1519.     textReg.setValue( "stack error" );
  1520.     entered=3;
  1521.   } else
  1522.     numstack[numsp++]=num;
  1523. }
  1524.  
  1525.  
  1526.  
  1527. static
  1528. double PopNum()
  1529. {
  1530.     if ( rpn ) {
  1531.         double tmp = numstack[0];
  1532.         numstack[0] = numstack[1];
  1533.         numstack[1] = numstack[2];
  1534.         return(tmp);
  1535.     }
  1536.     if ( numsp == 0 ) {
  1537.         textReg.setValue( "stack error" );
  1538.         entered=3;
  1539.         return 0.0;
  1540.     } else
  1541.       return( numstack[--numsp] );
  1542. }
  1543.  
  1544.  
  1545.  
  1546. static
  1547. int isopempty()
  1548. {
  1549.   return( opsp ? 0 : 1 );
  1550. }
  1551.  
  1552.  
  1553. static 
  1554. int priority(int op)
  1555. {
  1556.     switch ( op ) {
  1557.         case kPOW: return(2);
  1558.         case kMUL:
  1559.         case kDIV: return(1);
  1560.         case kADD:
  1561.         case kSUB: return(0);
  1562.         }
  1563.     return 0;
  1564. }
  1565.  
  1566.  
  1567. void parse_double (char *src, char *fmt, double *dp)
  1568. {
  1569.     int olderrno = errno;
  1570.  
  1571.     (void) sscanf (src, fmt, dp);
  1572.     errno = olderrno;
  1573.     return;
  1574. }
  1575.  
  1576.  
  1577. static void
  1578. eef()
  1579. {
  1580.   flagINV=0;
  1581.   if ( clrdisp ) {
  1582.       if ( rpn && lift_enabled )
  1583.     PushNum( dnum );
  1584. //      strcpy(dispstr, rpn ? "1" : "0");
  1585.       textReg.setValue( "1" );
  1586.   }
  1587.   if ( !exponent ) {
  1588. //    strcat( dispstr, "E+" );
  1589.     textReg.addChar( 'E' );
  1590.     textReg.addChar( '+' );
  1591.     DrawDisplay();
  1592.     exponent = textReg.getLength() - 1;
  1593. //    exponent=strlen(dispstr)-1;  /* where the '-' goes */
  1594.   }
  1595.   clrdisp=0;
  1596.   entered=1;
  1597. }
  1598.  
  1599.  
  1600. static void
  1601. ResetCalc()
  1602. {
  1603.     flagM = flagINV = flagPAREN = 0;  drgmode = DEG;
  1604. //    setflag(XCalc_MEMORY, False);
  1605. //    setflag(XCalc_INVERSE, False);
  1606. //    setflag(XCalc_PAREN, False);
  1607. //    setflag(XCalc_RADIAN, False);
  1608. //    setflag(XCalc_GRADAM, False);
  1609. //    setflag(XCalc_DEGREE, True);
  1610.     textReg.setValue("0");
  1611.     DrawDisplay();
  1612.     ClearStacks();
  1613.     drg2rad = PI/180.0;
  1614.     rad2drg = 180.0/PI;
  1615. }
  1616.  
  1617.  
  1618. static void
  1619. offf()
  1620. {
  1621.   /* full reset */
  1622.   int i;
  1623.   ResetCalc();
  1624.   entered = clrdisp = 1;
  1625.   lift_enabled = 0;
  1626.   dnum = mem[0] = 0.0;
  1627.   if (rpn)
  1628.       for (i = 1 ; i < XCALC_MEMORY; i++)
  1629.       mem[i] = 0.0;
  1630.   exponent = Dpoint = 0;
  1631.   DrawDisplay();
  1632. }
  1633.  
  1634.  
  1635. static void
  1636. clearf()
  1637. {
  1638.   flagINV = 0;
  1639.   if (CLR && !rpn) { /* clear all */
  1640.     ClearStacks();
  1641.     flagPAREN = 0;
  1642.   }
  1643.   CLR++;
  1644.   exponent = Dpoint = 0;
  1645.   clrdisp = 1;
  1646.   entered = 1;
  1647.   textReg.setValue( "0" );
  1648.   DrawDisplay();
  1649. }
  1650.  
  1651.  
  1652. static void
  1653. bkspf()
  1654. {
  1655.   
  1656.   lift_enabled = 0;
  1657.   
  1658.   if (! flagINV) {
  1659.     if (entered!=1 || clrdisp)
  1660.       return;
  1661.     if ( textReg.getLength() > 0 )
  1662.       textReg.removeTail();
  1663.     if ( textReg.getLength() == 0 ) {
  1664.       textReg.setValue( "0" );
  1665.       clrdisp++;
  1666.     }
  1667.   }
  1668.   else
  1669.     {
  1670.       textReg.setValue( "0" );
  1671.       dnum = 0.0;
  1672.       clrdisp++;
  1673.       flagINV = 0;
  1674.     }
  1675.   DrawDisplay();
  1676. }
  1677.  
  1678.  
  1679. static void
  1680. Quit()
  1681. {
  1682.     XtDestroyApplicationContext( appContext );
  1683.     exit( 0 );
  1684. }
  1685.  
  1686.  
  1687.  
  1688. static void 
  1689. ClearStacks()
  1690. {
  1691.     if ( rpn )
  1692.       numstack[0] = numstack[1] = numstack[2] = 0.;
  1693.     opsp=numsp=0;
  1694. }
  1695.  
  1696.  
  1697.  
  1698. static
  1699. int pre_op( int keynum)
  1700. {
  1701.     if ( keynum == -1 ) 
  1702.       return(0);
  1703.  
  1704.     errno = 0;                  /* for non-IEEE machines */
  1705.  
  1706.     if ( ( entered == 3) && !( keynum == kCLR || keynum == kOFF )) {
  1707.       if (rpn) {
  1708.         clrdisp++;
  1709.       } else {
  1710. //        ringbell();
  1711.         return( 1 );      /* the intent was probably not to do the operation */
  1712.       }
  1713.     }
  1714.  
  1715.     if (keynum != kCLR) 
  1716.       CLR = 0;
  1717.     return(0);
  1718. }
  1719.  
  1720.  
  1721. static void
  1722. rparf()
  1723. {
  1724.   double PopNum();
  1725.  
  1726.   flagINV=0;
  1727.   if (!entered)
  1728.     return;
  1729.  
  1730.   if (!flagPAREN)
  1731.     return;
  1732.   
  1733.   clrdisp++;
  1734.   Dpoint=exponent=0;
  1735.  
  1736.   char *tmpStr = textReg.getValue();
  1737.   if (entered==1)
  1738.     parse_double( tmpStr, "%lf", &dnum );
  1739.   entered=2;
  1740.  
  1741.   PushNum(dnum);
  1742.   while ( !isopempty() && ( lastop = PopOp()) != kLPAR ) {
  1743.     /* do all pending ops, back to left paren */
  1744.     dnum=PopNum();
  1745.     acc=PopNum();
  1746.     switch ( lastop ) {
  1747.     case kADD:  acc += dnum;
  1748.                 break;
  1749.     case kSUB:  acc -= dnum;
  1750.                 break;
  1751.     case kMUL:  acc *= dnum;
  1752.                 break;
  1753.     case kDIV:  acc /= dnum;
  1754.                 break;
  1755.     case kPOW:  acc = pow( acc, dnum );
  1756.                 break;
  1757.     }
  1758.     dnum=acc;
  1759.     PushNum( dnum );
  1760.   }
  1761.   (void) PopNum();
  1762.   flagPAREN--;
  1763.   entered=2;
  1764.   sprintf( tmpStr ,"%.8g", dnum );
  1765.   textReg.setValue( tmpStr );
  1766.   DrawDisplay();
  1767. }
  1768.  
  1769.  
  1770. static void   
  1771. lparf()
  1772.   flagINV=0;
  1773.   PushOp( kLPAR );
  1774.   flagPAREN++;
  1775.   DrawDisplay();
  1776. }
  1777.  
  1778.  
  1779. static void
  1780. entrf()
  1781. {
  1782.   flagINV=0;
  1783.   if ( !entered )
  1784.     return;
  1785.  
  1786.   clrdisp=CLR=1;
  1787.   Dpoint=exponent=0;
  1788.  
  1789.   char *tmpStr = textReg.getValue();
  1790.   if (entered==1)
  1791.     parse_double( tmpStr, "%lf", &dnum );
  1792.   entered=2;
  1793.   memop = kENTR;
  1794.   PushNum( dnum );
  1795.   lift_enabled = 0;
  1796. }
  1797.  
  1798.  
  1799.  
  1800. static void
  1801. equf()
  1802. {
  1803.   flagINV=0;
  1804.   if (!entered)
  1805.     return;
  1806.  
  1807.   clrdisp = CLR =1;
  1808.   Dpoint = exponent =0;
  1809.  
  1810.   char *tmpStr = textReg.getValue();
  1811.   if ( entered == 1 )
  1812.     parse_double( tmpStr,"%lf", &dnum );
  1813.   
  1814.   entered = 2;
  1815.  
  1816.   PushNum( dnum );
  1817.  
  1818.   while ( !isopempty() ) {  /* do all pending ops */
  1819.     dnum = PopNum();
  1820.     acc = PopNum();
  1821.     lastop = PopOp();
  1822.     switch ( lastop ) {
  1823.     case kADD:  acc += dnum;
  1824.                 break;
  1825.     case kSUB:  acc -= dnum;
  1826.                 break;
  1827.     case kMUL:  acc *= dnum;
  1828.                 break;
  1829.     case kDIV:  acc /= dnum;
  1830.                 break;
  1831.     case kPOW:  acc = pow( acc, dnum );
  1832.                 break;
  1833.     case kLPAR: flagPAREN--;
  1834.                 PushNum( acc );
  1835.                 break;
  1836.     }
  1837.     dnum = acc;
  1838.     PushNum( dnum );
  1839.   }
  1840.  
  1841.   sprintf( tmpStr,"%.8g", dnum );
  1842.   textReg.setValue( tmpStr );
  1843.   DrawDisplay();
  1844.   viewer->render();
  1845. }
  1846.  
  1847.  
  1848. static void
  1849. drgf()
  1850. {
  1851.   char *tmpStr;
  1852.   if (flagINV) {
  1853.     tmpStr = textReg.getValue();
  1854.     if (entered==1)
  1855.       parse_double(tmpStr,"%lf",&dnum);
  1856.     switch (drgmode) {
  1857.     case DEG:  dnum=dnum*PI/180.0;    break;
  1858.     case RAD:  dnum=dnum*200.0/PI;    break;
  1859.     case GRAD: dnum=dnum*90.0/100.0;  break;
  1860.     }
  1861.     entered=2;
  1862.     clrdisp=1;
  1863.     flagINV=0;
  1864.     sprintf( tmpStr,"%.8g",dnum);
  1865.     textReg.setValue( tmpStr );
  1866.   }
  1867.                          
  1868.   flagINV=0;
  1869.   drgmode = (drgmode + 1) % 3;
  1870.   switch (drgmode) {
  1871.   case DEG:  drg2rad=PI / 180.0;
  1872.          rad2drg=180.0 / PI;
  1873.          break;
  1874.   case RAD:  drg2rad=1.0;
  1875.          rad2drg=1.0;
  1876.          break;
  1877.   case GRAD: drg2rad=PI / 200.0;
  1878.          rad2drg=200.0 / PI;
  1879.          break;
  1880.   }
  1881.   DrawDisplay();
  1882. }
  1883.  
  1884.         
  1885. static void
  1886. decf()
  1887. {
  1888.   flagINV=0;
  1889.   if (clrdisp) {
  1890.       if (rpn)
  1891.         PushNum(dnum);
  1892.       textReg.setValue( "0" );
  1893. //      strcpy(dispstr,"0");
  1894.   }
  1895.   if (!Dpoint) {
  1896.     textReg.addChar( '.' );
  1897. //    strcat(dispstr,".");
  1898.     DrawDisplay();
  1899.     Dpoint++;
  1900.   }
  1901.   clrdisp=0;
  1902.   entered=1;
  1903. }
  1904.  
  1905.  
  1906.  
  1907. static void
  1908. negf()
  1909. {
  1910.   flagINV=0;
  1911.   if ( exponent ) {       /* neg the exponent */
  1912.     if ( textReg.getChar( exponent ) == '-' )
  1913.       textReg.replaceChar( exponent, '+');
  1914.     else
  1915.       textReg.replaceChar( exponent, '+');
  1916.     DrawDisplay();
  1917.     return;
  1918.   }
  1919.  
  1920.   if ( strcmp("0", textReg.getValue()) == 0 )
  1921.     return;                           /* don't neg a zero */
  1922.  
  1923.   if ( textReg.getChar( 0 ) == '-' )      /* already neg-ed */
  1924.     textReg.removeHead();
  1925.   else                                     /* not neg-ed.  add a '-' */
  1926.     textReg.addHead( '-' );
  1927.  
  1928.  
  1929.   if ( entered == 2 )
  1930.     dnum = -1.0 * dnum;
  1931.   DrawDisplay();
  1932. }
  1933.  
  1934.  
  1935.  
  1936. static void 
  1937. invf()
  1938. {
  1939.   flagINV = ~flagINV;
  1940.   DrawDisplay();
  1941. }
  1942.  
  1943.  
  1944. static void
  1945. add( int )
  1946. {
  1947.     XCALC_PRE_OP(kADD);
  1948.     rpn ? twof(kADD) : twoop(kADD);
  1949.     post_op();
  1950. }
  1951.  
  1952.  
  1953. static void 
  1954. subtract( int )
  1955. {
  1956.     XCALC_PRE_OP(kSUB);
  1957.     rpn ? twof(kSUB) : twoop(kSUB);
  1958.     post_op();
  1959. }
  1960.  
  1961.  
  1962. void divide( int )
  1963. {
  1964.     XCALC_PRE_OP(kDIV);
  1965.     rpn  ? twof(kDIV) : twoop(kDIV);
  1966.     post_op();
  1967. }
  1968.  
  1969.  
  1970. void sum( int )
  1971. {
  1972.     XCALC_PRE_OP(kSUM);
  1973.     rpn ? memf(kSUM) : oneop(kSUM);
  1974.     post_op();
  1975. }
  1976.    
  1977.  
  1978. void multiply( int )
  1979. {
  1980.     XCALC_PRE_OP(kMUL);
  1981.     rpn ? twof(kMUL) : twoop(kMUL);
  1982.     post_op();
  1983. }
  1984.    
  1985.  
  1986. void negate( int )
  1987. {
  1988.     XCALC_PRE_OP(kNEG);
  1989.     negf();
  1990.     post_op();
  1991. }
  1992.  
  1993.  
  1994. void rightParen( int )
  1995. {
  1996.     XCALC_PRE_OP(kRPAR);
  1997.     rparf();
  1998.     post_op();
  1999. }
  2000.    
  2001.  
  2002. void leftParen( int )
  2003. {
  2004.     XCALC_PRE_OP(kLPAR);
  2005.     lparf();
  2006.     post_op();
  2007. }
  2008.  
  2009.  
  2010. void equal( int )
  2011. {
  2012.     XCALC_PRE_OP(kEQU);
  2013.     equf();
  2014.     post_op();
  2015. }
  2016.  
  2017.  
  2018. void enter( int )
  2019. {
  2020.     XCALC_PRE_OP(kENTR);
  2021.     entrf();
  2022.     post_op();
  2023. }
  2024.  
  2025.    
  2026. void clearit( int )
  2027. {
  2028.     XCALC_PRE_OP(kCLR);
  2029.     clearf();
  2030.     post_op();
  2031. }
  2032.    
  2033.  
  2034. static
  2035. void decimal( int )
  2036. {
  2037.     XCALC_PRE_OP(kDEC);
  2038.     decf();
  2039.     post_op();
  2040. }
  2041.  
  2042.  
  2043. void degree(int)
  2044. {
  2045.     XCALC_PRE_OP(kDRG);
  2046.     drgf();
  2047.     post_op();
  2048. }
  2049.  
  2050.  
  2051. void reciprocal( int )
  2052. {
  2053.     XCALC_PRE_OP(kRECIP);
  2054.     oneop(kRECIP);
  2055.     post_op();
  2056. }
  2057.    
  2058.  
  2059. void squareRoot( int )
  2060. {
  2061.     XCALC_PRE_OP(kSQRT);
  2062.     oneop(kSQRT);
  2063.     post_op();
  2064. }
  2065.    
  2066.  
  2067. void power( int )
  2068. {
  2069.     XCALC_PRE_OP(kPOW);
  2070.     rpn ? twof(kPOW) : twoop(kPOW);
  2071.     post_op();
  2072. }
  2073.  
  2074.  
  2075. void back( int )
  2076. {
  2077.     XCALC_PRE_OP(kBKSP);
  2078.     bkspf();
  2079.     post_op();
  2080. }
  2081.  
  2082.  
  2083. void cosine( int )
  2084. {
  2085.     XCALC_PRE_OP(kCOS);
  2086.     oneop(kCOS);
  2087.     post_op();
  2088. }
  2089.  
  2090.  
  2091. void e( int )
  2092. {
  2093.     XCALC_PRE_OP(kE);
  2094.     oneop(kE);
  2095.     post_op();
  2096. }
  2097.  
  2098.  
  2099. void epower( int )
  2100. {
  2101.     XCALC_PRE_OP(kEXP);
  2102.     oneop(kEXP);
  2103.     post_op();
  2104. }
  2105.  
  2106.  
  2107.  
  2108. void factorial( int )
  2109. {
  2110.     XCALC_PRE_OP(kFACT);
  2111.     oneop(kFACT);
  2112.     post_op();
  2113. }
  2114.  
  2115.  
  2116. void inverse( int )
  2117. {
  2118.     XCALC_PRE_OP(kINV);
  2119.     invf();
  2120.     post_op();
  2121. }
  2122.    
  2123.  
  2124.  
  2125. void naturalLog( int )
  2126. {
  2127.     XCALC_PRE_OP(kLN);
  2128.     oneop(kLN);
  2129.     post_op();
  2130. }
  2131.    
  2132.  
  2133. void pi( int )
  2134. {
  2135.     XCALC_PRE_OP(kPI);
  2136.     oneop(kPI);
  2137.     post_op();
  2138. }
  2139.    
  2140.  
  2141.  
  2142. void sine( int )
  2143. {
  2144.     XCALC_PRE_OP(kSIN);
  2145.     oneop(kSIN);
  2146.     post_op();
  2147. }
  2148.  
  2149.  
  2150. void square( int )
  2151. {
  2152.     XCALC_PRE_OP(kSQR);
  2153.     oneop(kSQR);
  2154.     post_op();
  2155. }
  2156.  
  2157.  
  2158. void tangent( int )
  2159. {
  2160.     XCALC_PRE_OP(kTAN);
  2161.     oneop(kTAN);
  2162.     post_op();
  2163. }
  2164.    
  2165.  
  2166. void logarithm( int )
  2167. {
  2168.     XCALC_PRE_OP(kLOG);
  2169.     oneop(kLOG);
  2170.     post_op();
  2171. }
  2172.  
  2173.  
  2174. void scientific( int )
  2175. {
  2176.     XCALC_PRE_OP(kEE);
  2177.     eef();
  2178.     post_op();
  2179. }
  2180.  
  2181.  
  2182. static void
  2183. quit( int )
  2184. {
  2185.   Quit();
  2186. }
  2187.  
  2188.  
  2189. void off( int )
  2190. {
  2191.     XCALC_PRE_OP(kOFF);
  2192.     offf();
  2193.     post_op();
  2194. }
  2195.    
  2196.